

#include <string>
#include <unordered_map>
#include <cstdint>
#include "replace_chinese_pun.h"


// UTF-8字符处理工具函数
uint32_t replace_chinese_pun::utf8_to_codepoint(const std::string& s, size_t& index) {
    uint32_t codepoint = 0;
    unsigned char c = s[index];
    if (c <= 0x7F) {
        codepoint = c;
        index += 1;
    } else if ((c & 0xE0) == 0xC0) {
        codepoint = (c & 0x1F) << 6 | (s[index+1] & 0x3F);
        index += 2;
    } else if ((c & 0xF0) == 0xE0) {
        codepoint = (c & 0x0F) << 12 | (s[index+1] & 0x3F) << 6 | (s[index+2] & 0x3F);
        index += 3;
    } else if ((c & 0xF8) == 0xF0) {
        codepoint = (c & 0x07) << 18 | (s[index+1] & 0x3F) << 12 |
                   (s[index+2] & 0x3F) << 6 | (s[index+3] & 0x3F);
        index += 4;
    }
    return codepoint;
}

std::string replace_chinese_pun::codepoint_to_utf8(uint32_t codepoint) {
    if (codepoint <= 0x7F) {
        return std::string{1, static_cast<char>(codepoint)};
    } else if (codepoint <= 0x7FF) {
        return std::string({
            static_cast<char>(0xC0 | (codepoint >> 6)),
            static_cast<char>(0x80 | (codepoint & 0x3F))
        });
    } else if (codepoint <= 0xFFFF) {
        return std::string({
            static_cast<char>(0xE0 | (codepoint >> 12)),
            static_cast<char>(0x80 | ((codepoint >> 6) & 0x3F)),
            static_cast<char>(0x80 | (codepoint & 0x3F))
        });
    } else {
        return std::string({
            static_cast<char>(0xF0 | (codepoint >> 18)),
            static_cast<char>(0x80 | ((codepoint >> 12) & 0x3F)),
            static_cast<char>(0x80 | ((codepoint >> 6) & 0x3F)),
            static_cast<char>(0x80 | (codepoint & 0x3F))
        });
    }
}

// 主替换函数
std::string replace_chinese_pun::replace_punctuation(const std::string& input) {
    const std::unordered_map<uint32_t, uint32_t> PUNCTUATION_MAP = {
        {0x3001, 0x002C}, // 、 → ,
        {0x3002, 0x002E}, // 。 → .
        {0xFF0C, 0x002C}, // ， → ,
        {0xFF1F, 0x003F}, // ？ → ?
        {0xFF01, 0x0021}, // ！ → !
        {0xFF1B, 0x003B}, // ； → ;
        {0xFF1A, 0x003A}, // ： → :
        {0x201C, 0x0022}, // “ → "
        {0x201D, 0x0022}, // ” → "
        {0xFF08, 0x0028}, // （ → (
        {0xFF09, 0x0029}  // ） → )
    };

    std::string result;
    size_t i = 0;
    while (i < input.size()) {
        size_t start = i;
        uint32_t cp = utf8_to_codepoint(input, i);

        auto it = PUNCTUATION_MAP.find(cp);
        if (it != PUNCTUATION_MAP.end()) {
            if (it->second != 0x0028 && it->second != 0x0029)
                result += codepoint_to_utf8(it->second) + " ";
            else
            result += codepoint_to_utf8(it->second);
        } else {
            result.append(input.substr(start, i - start));
        }
    }
    return result;
}
